from gzip import compress
from json import dumps
import functools

import tornado.web
from tornado.web import RequestHandler


RoleAdmin = 3
RoleTeacher = 2
RoleStudent = 1
RoleGuest = 0


def check_gzip(headers) -> bool:
    return 'Accept-Encoding' in headers and 'gzip' in headers['Accept-Encoding']


def gzip_compress(data: str) -> bytes:
    return compress(bytes(data, 'utf-8'))


class APIBaseHandler(RequestHandler):
    CORS_ENABLED = True
    GZIP_ENABLED = True
    SUPPORTED_METHODS = 'GET, POST'

    def prepare(self):
        self.db = self.settings['db']
        self.role = self.get_secure_cookie('role')
        self.role = int(self.role) if self.role else RoleGuest

    def get_current_user(self):
        current_user = self.get_secure_cookie('user')
        return current_user.decode() if current_user else None

    def write_json(self, response_body=None, status_code=200):
        self.set_status(status_code)
        self.set_header('Content-Type', 'application/json')
        if self.CORS_ENABLED:
            self.set_header('Access-Control-Allow-Origin', '*')
            self.set_header('Access-Control-Allow-Headers', '*')
            self.set_header('Access-Control-Allow-Methods',
                            self.SUPPORTED_METHODS)
        if self.GZIP_ENABLED and check_gzip(self.request.headers):
            self.set_header('Content-Encoding', 'gzip')
            self.write(gzip_compress(dumps(response_body)))
        else:
            self.write(response_body)


def check_role(role: int = RoleStudent):
    def check_role_decorator(fn):
        @functools.wraps(fn)
        def wrapper(self: APIBaseHandler, *args, **kwargs):
            if self.role < role:
                return self.write_json({'self.role': self.role, 'require': role}, status_code=403)
            return fn(self, *args, **kwargs)
        return wrapper
    return check_role_decorator


def get_id(uri: str):
    return uri.split('?')[0].split('/')[-1]


__all__ = ['APIBaseHandler', 'RoleAdmin', 'RoleTeacher',
           'RoleStudent', 'RoleGuest', 'check_role', 'get_id']
